package ru.ifmo.rybakov.muclumon.utils;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.util.List;

import javax.persistence.EntityManager;
import javax.persistence.EntityTransaction;
import javax.persistence.Query;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import ru.ifmo.rybakov.muclumon.Database;
import ru.ifmo.rybakov.muclumon.Properties;
import ru.ifmo.rybakov.muclumon.PropertyManager;
import ru.ifmo.rybakov.muclumon.PropertyValueFactory;
import ru.ifmo.rybakov.muclumon.Task;

public class GAMESSParser {

	private static final Logger logger = LoggerFactory.getLogger(GAMESSParser.class); 
	
	/**
	 * @param args
	 */
	public static void main(String[] args) {
		if (args.length < 1) {
			logger.error("No arguments, run as <app> <file-path>. Terminating.");
			return;
		}
		String filePath = args[0];
		logger.info("GAMESS parser syas 'hello'. Path: {}", filePath);
		
		// now look for files like orca.#.out under path
		File dir = new File(filePath);
		String files[] = dir.list();
		if (files == null) {
			logger.error("Invalid path. Terminating.");
		} else {
			for (String f : files) {
				if (f.endsWith(".out")) {
					String numString = f.substring(0, f.indexOf(".out"));
					Integer num = Integer.valueOf(numString);
					
					// now parse file, extract data and update task in database
					process(filePath + "/" + f, num);
				}
			}
		}
	}
	
	public static void process(String fileName, Integer taskId) {
		logger.info("Processing {}", fileName + "#" + taskId);
		BufferedReader reader = null;
		try {
			reader = new BufferedReader(new FileReader(fileName));
			String line;
			while ((line = reader.readLine()) != null) {
				if (!line.startsWith(" TOTAL NUMBER OF BASIS SET SHELLS")) continue; // read until required line
				String value = line.substring(line.indexOf("=") + 1);
				Double bss = Double.valueOf(value.trim());
				line = reader.readLine();
				value = line.substring(line.indexOf("=") + 1);
				Double gbf = Double.valueOf(value.trim());
				logger.debug("Paremeters extracted: {}, {}", new Object[] { bss, gbf });
				
				EntityManager em = Database.getEntityManagerFactory().createEntityManager();
				try {
					Query query = em.createQuery("SELECT t FROM Task t WHERE t.foreignId = :id");
					query.setParameter("id", taskId);
					List<Task> tasks = query.getResultList();
					for (Task task : tasks) { 
						if (task == null) {
							logger.warn("No task found for id={}, skipping", taskId);
							continue;
						}
						EntityTransaction t = em.getTransaction();
						try {
							t.begin();
							if (task.isPropertySet(PropertyManager.get(Properties.GAMESS_BASIS_SET_SHELLS))) {
								logger.warn("Property {} is already set on task {}", new Object[] { Properties.GAMESS_BASIS_SET_SHELLS, taskId });
							} else {
								task.addPropertyValue(PropertyValueFactory.createNumericValue(Properties.GAMESS_BASIS_SET_SHELLS, bss));
							}
							if (task.isPropertySet(PropertyManager.get(Properties.BASIS_FUNCTIONS))) {
								logger.warn("Property {} is already set on task {}", new Object[] { Properties.BASIS_FUNCTIONS, taskId });
							} else {
								task.addPropertyValue(PropertyValueFactory.createNumericValue(Properties.BASIS_FUNCTIONS, gbf));
							}
							t.commit();
						} finally {
							if (t.isActive()) {
								t.rollback();
							}
						}
					}
				} finally {
					em.close();
				}
			}
		} catch (IOException e) {
			logger.error("Unexpected I/O exception", e);
		} finally {
			try {
				reader.close();
			} catch (Throwable e) {};
		}
	}

}
